package cn.turboinfo.fuyang.api.provider.common.component.custom.interceptor

import cn.turboinfo.fuyang.api.entity.common.enumeration.custom.ServiceCustomStatus
import cn.turboinfo.fuyang.api.entity.common.event.WrapperApplicationEvent
import cn.turboinfo.fuyang.api.entity.common.event.custom.ServiceCustomStatusChangedEvent
import cn.turboinfo.fuyang.api.entity.common.pojo.custom.QServiceCustom
import cn.turboinfo.fuyang.api.entity.common.pojo.custom.ServiceCustomStatusLog
import cn.turboinfo.fuyang.api.provider.common.framework.jpa.interceptor.FlushDirtyInterceptor
import cn.turboinfo.fuyang.api.provider.common.framework.jpa.interceptor.SaveInterceptor
import cn.turboinfo.fuyang.api.provider.common.repository.database.custom.ServiceCustomPO
import org.hibernate.type.Type
import org.springframework.context.ApplicationContext
import org.springframework.stereotype.Component
import org.springframework.transaction.support.TransactionSynchronization
import org.springframework.transaction.support.TransactionSynchronizationManager
import java.io.Serializable

/**
 * 自动记录每个状态变更的时间点
 */
@Component
class ServiceCustomStatusHistoryInterceptor(
    private val applicationContext: ApplicationContext,
) : SaveInterceptor, FlushDirtyInterceptor {

    override fun onSave(
        entity: Any,
        id: Serializable?,
        state: Array<Any>,
        propertyNames: Array<out String>,
        types: Array<out Type>
    ): Boolean {
        val index = propertyNames.indexOf(QServiceCustom.customStatusHistory)

        (entity as ServiceCustomPO)
            .also {
                state[index] = listOf(
                    ServiceCustomStatusLog(it.customStatus, null, 0, 0, it.updatedTime)
                )
            }

        return true
    }

    override fun onFlushDirty(
        entity: Any,
        id: Serializable,
        currentState: Array<Any>,
        previousState: Array<out Any>,
        propertyNames: Array<out String>,
        types: Array<out Type>
    ): Boolean {
        val index = propertyNames.indexOf(QServiceCustom.customStatus)

        if (previousState[index] != currentState[index]) {
            (entity as ServiceCustomPO)
                .also {
                    val log = ServiceCustomStatusLog(
                        currentState[index] as ServiceCustomStatus,
                        previousState[index] as ServiceCustomStatus,
                        it.companyId,
                        it.staffId,
                        it.updatedTime,
                    )
                    currentState[propertyNames.indexOf(QServiceCustom.customStatusHistory)] =
                        if (it.customStatusHistory == null) {
                            listOf(log)
                        } else {
                            it.customStatusHistory + log
                        }

                    TransactionSynchronizationManager.registerSynchronization(object : TransactionSynchronization {
                        override fun afterCommit() {
                            applicationContext.publishEvent(
                                WrapperApplicationEvent(
                                    ServiceCustomStatusChangedEvent.builder()
                                        .serviceCustomId(entity.id)
                                        .fromStatus(previousState[index] as ServiceCustomStatus)
                                        .status(currentState[index] as ServiceCustomStatus)
                                        .build()
                                )
                            )
                        }
                    })
                }
            return true
        }

        return false
    }

    override fun isSupported(
        entity: Any,
        id: Serializable,
        currentState: Array<out Any>,
        previousState: Array<out Any>,
        propertyNames: Array<out String>,
        types: Array<out Type>
    ): Boolean {
        return entity is ServiceCustomPO
    }

    override fun isSupported(
        entity: Any,
        id: Serializable?,
        state: Array<out Any>,
        propertyNames: Array<out String>,
        types: Array<out Type>
    ): Boolean {
        return entity is ServiceCustomPO
    }
}
